//
//  ShaderInitialize.cpp
//  GLDemo
//
//  Created by wenqi on 5/23/14.
//  Copyright (c) 2014 xiewneqi. All rights reserved.
//

#include <stdlib.h>
#include <iostream>
#include "shader_initialize.h"

void readShaderSource (const char* shaderFilePath, PointerArray<char>& pa)
{
    
    FILE* fp = fopen (shaderFilePath, "r");
    if (fp == 0)
    {
        throw "读取文件出错";
    }
    
    fseek (fp, 0, SEEK_END);
    long size = ftell (fp);
    fseek (fp, 0, SEEK_SET);
    pa.Malloc ((unsigned int)size + 1);
    char* buff = pa.GetBuffer ();
    fread (buff, 1, size, fp);
    buff[size] = '\0';
    fclose (fp);
}

GLuint InitShader (const char* vertexShaderFilePath, const char* fragmentShaderFilePath)
{
    struct Shader
    {
        const char*             fileName;
        GLenum                  type;
        PointerArray<char>      source;
    };
    
    Shader shaders[2] =
    {
        {vertexShaderFilePath, GL_VERTEX_SHADER},
        {fragmentShaderFilePath, GL_FRAGMENT_SHADER}
    };
    
    GLuint program = glCreateProgram ();
    for (int i = 0; i < 2; ++ i)
    {
        Shader& s = shaders[i];
        try
        {
            readShaderSource (s.fileName, s.source);
        }
        catch (char* message)
        {
            std::cerr<< "Failed to read " << s.fileName << ", Error: " << message << std::endl;
            exit (EXIT_FAILURE);
        }
        
        GLuint shader = glCreateShader (s.type);
        glShaderSource (shader, 1, (const GLchar**)(&s.source.GetBuffer ()), NULL);
        glCompileShader (shader);
        GLint compiled;
        glGetShaderiv (shader, GL_COMPILE_STATUS, &compiled);
        if (compiled == 0)
        {
            GLint logSize;
            glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &logSize);
            PointerArray<char> logMsgBuffer;
            logMsgBuffer.Malloc (logSize);
            glGetShaderInfoLog (shader, logSize, NULL, logMsgBuffer.GetBuffer ());
            std::cerr << "Error compile shader " << s.fileName << ", Error: " << logMsgBuffer.GetBuffer () << std::endl;
            exit (EXIT_FAILURE);
        }
        else
        {
            glAttachShader (program, shader);
        }
    }
    
    glLinkProgram (program);
    GLint linked;
    glGetProgramiv (program, GL_LINK_STATUS, &linked);
    if (linked == 0)
    {
        GLint logSize;
        glGetProgramiv (program, GL_INFO_LOG_LENGTH, &logSize);
        PointerArray<char> logMsgBuffer;
        logMsgBuffer.Malloc (logSize);
        glGetProgramInfoLog (program, logSize, NULL, logMsgBuffer.GetBuffer ());
        std::cerr << "Error Link program , Error: " << logMsgBuffer.GetBuffer () << std::endl;
        exit (EXIT_FAILURE);
    }
    return program;
}

